
package com.shop.cloud.mall.api.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shop.cloud.common.core.constant.CacheConstants;
import com.shop.cloud.common.core.constant.CommonConstants;
import com.shop.cloud.common.core.constant.SecurityConstants;
import com.shop.cloud.common.core.util.IpUtils;
import com.shop.cloud.common.core.util.R;
import com.shop.cloud.common.core.util.SensitiveUtils;
import com.shop.cloud.common.core.util.SpringContextHolder;
import com.shop.cloud.common.data.tenant.TenantContextHolder;
import com.shop.cloud.common.portal.constant.PortalConstants;
import com.shop.cloud.common.portal.interceptor.ThirdSessionInterceptor;
import com.shop.cloud.common.portal.util.ApiUtil;
import com.shop.cloud.mall.api.mapper.UserPointsMapper;
import com.shop.cloud.common.portal.util.ThirdSessionHolder;
import com.shop.cloud.mall.common.config.MallConfigProperties;
import com.shop.cloud.mall.common.constant.MallConstants;
import com.shop.cloud.mall.common.dto.UserInfoLoginDTO;
import com.shop.cloud.mall.common.entity.*;
import com.shop.cloud.mall.api.mapper.UserInfoMapper;
import com.shop.cloud.weixin.common.feign.FeignWxAppService;
import com.shop.cloud.weixin.common.feign.FeignWxUserService;
import com.shop.cloud.weixin.common.constant.WxConstant;
import com.shop.cloud.weixin.common.dto.LoginDTO;
import com.shop.cloud.weixin.common.dto.WxOpenDataDTO;
import com.shop.cloud.common.portal.entity.ThirdSession;
import com.shop.cloud.weixin.common.entity.WxApp;
import com.shop.cloud.weixin.common.entity.WxUser;
import com.shop.cloud.mall.api.service.DistributionConfigService;
import com.shop.cloud.mall.api.service.PointsConfigService;
import com.shop.cloud.mall.api.service.PointsRecordService;
import com.shop.cloud.mall.api.service.UserInfoService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.klock.annotation.Klock;
import org.springframework.boot.autoconfigure.klock.model.LockTimeoutStrategy;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 商城用户
 *
 * @author
 * @date 2019-12-04 11:09:55
 */
@Slf4j
@Service
@AllArgsConstructor
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

	private final FeignWxUserService feignWxUserService;
	private final PointsConfigService pointsConfigService;
	private final PointsRecordService pointsRecordService;
	private final RedisTemplate redisTemplate;
	private final FeignWxAppService feignWxAppService;
	private final MallConfigProperties mallConfigProperties;
	private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
	private final DistributionConfigService distributionConfigService;
	private final UserPointsMapper userPointsMapper;

	/**
	 * 解决@Cacheable注解缓存方法内部调用失效的问题
	 * https://blog.csdn.net/chris_hhao/article/details/105079533
	 * @return
	 */
	public UserInfoService getUserInfoService() {
		return SpringContextHolder.getBean(UserInfoServiceImpl.class);
	}

	@Override
	@Cacheable(value = CacheConstants.APP_USER_INFO_CACHE, key = "#id", unless = "#result == null")
	public UserInfo getById(Serializable id) {
		return baseMapper.selectById(id);
	}

	@Override
	@CacheEvict(value = CacheConstants.APP_USER_INFO_CACHE, key = "#entity.getId()")
	@Klock(name = "UserInfo", keys = {"#entity.getId()"}, lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
	public boolean updateById(UserInfo entity) {
		return super.updateById(entity);
	}

	@Override
	@CacheEvict(value = CacheConstants.APP_USER_INFO_CACHE, key = "#updateWrapper.getEntity().getId()")
	@Klock(name = "UserInfo", keys = {"#updateWrapper.getEntity().getId()"}, lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
	public boolean update(Wrapper<UserInfo> updateWrapper) {
		return this.update(updateWrapper);
	}

	@Override
	@CacheEvict(value = CacheConstants.APP_USER_INFO_CACHE, key = "#id")
	@Klock(name = "UserInfo", keys = {"#id"}, lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
	public boolean removeById(Serializable id) {
		return super.removeById(id);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public UserInfo loginMa(LoginDTO loginDTO) {
		//查出wxapp信息
		R<WxApp> r = feignWxAppService.getById(loginDTO.getAppId(), SecurityConstants.FROM_IN);
		if(!r.isOk()){
			throw new RuntimeException(r.getMsg());
		}
		WxApp wxApp = r.getData();
		if(wxApp == null){
			throw new RuntimeException("无此小程序：" + loginDTO.getAppId() + "；请在后台添加");
		}
		TenantContextHolder.setTenantId(wxApp.getTenantId());
		//通过code获取微信用户信息
		R<WxUser> r1 = feignWxUserService.code2WxUserMa(loginDTO, SecurityConstants.FROM_IN);
		if(!r1.isOk()){
			throw new RuntimeException(r1.getMsg());
		}
		WxUser wxUser = r1.getData();
		UserInfo userInfo;
		if(StrUtil.isBlank(wxUser.getId())) {
			//新增微信用户
			wxUser.setAppId(wxApp.getId());
			wxUser.setAppType(wxApp.getAppType());
			R<WxUser> r4 = feignWxUserService.saveOrUpdate(wxUser, SecurityConstants.FROM_IN);
			if(!r4.isOk()){
				throw new RuntimeException(r4.getMsg());
			}
			wxUser = r4.getData();
		}
		if(StrUtil.isNotBlank(wxUser.getMallUserId())){
			userInfo = getUserInfoService().getById(wxUser.getMallUserId());
			if(userInfo != null){
				//分销关系上级绑定，用户类型 1、老用户
				userInfo.setSharerUserCode(loginDTO.getSharerUserCode());
				this.parentBind(MallConstants.DISTRIBUTION_USER_TYPE_1,userInfo);
			}else{
				userInfo = new UserInfo();
			}
		}else{
			//同一微信开放平台账号下的不同应用 同一用户的unionId是相同的
			if(StrUtil.isNotBlank(wxUser.getUnionId())){
				//如果该小程序用户有unionId，继续查找该unionId的其他小程序、公众号用户是否已经绑定商城用户，如有unionId相同的其他小程序、公众号用户，说明是同一人；直接绑定相同的商城用户，无需再次登录绑定
				R<List<WxUser>> r2 = feignWxUserService.getByUnionIdInside(wxUser.getUnionId(), wxUser.getId(), SecurityConstants.FROM_IN);
				List<WxUser> listWxUser = r2.getData();
				if(listWxUser != null && listWxUser.size() > 0){
					//取第一个unionId相同的微信用户
					WxUser wxUser2 = listWxUser.get(0);
					//查出此微信用户绑定的商城用户
					userInfo = getUserInfoService().getById(wxUser2.getMallUserId());
					//将该小程序用户绑定到该商城用户
					wxUser.setMallUserId(wxUser2.getMallUserId());
					feignWxUserService.saveOrUpdate(wxUser, SecurityConstants.FROM_IN);
					//分销关系上级绑定，用户类型 1、老用户
					userInfo.setSharerUserCode(loginDTO.getSharerUserCode());
					this.parentBind(MallConstants.DISTRIBUTION_USER_TYPE_1,userInfo);
				}else{
					userInfo = new UserInfo();
				}
			}else{
				userInfo = new UserInfo();
			}
		}
		String thirdSessionKey = "wx:" + wxUser.getId() + ":" + UUID.randomUUID();
		ThirdSession thirdSession = new ThirdSession();
		thirdSession.setTenantId(wxApp.getTenantId());
		thirdSession.setAppId(wxApp.getId());
		thirdSession.setSessionKey(wxUser.getSessionKey());
		thirdSession.setWxUserId(wxUser.getId());
		thirdSession.setOpenId(wxUser.getOpenId());
		thirdSession.setUserId(userInfo.getId());
		//将3rd_session和用户信息存入redis，并设置过期时间
		String key = ThirdSessionInterceptor.getSessionRedisKey(thirdSessionKey);
		redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(thirdSession) , CacheConstants.TIME_OUT_SESSION, TimeUnit.HOURS);
		userInfo.setThirdSession(thirdSessionKey);
		return userInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public UserInfo loginMp(LoginDTO loginDTO, HttpServletRequest request) {
		//查出wxapp信息
		R<WxApp> r = feignWxAppService.getById(loginDTO.getAppId(), SecurityConstants.FROM_IN);
		if(!r.isOk()){
			throw new RuntimeException(r.getMsg());
		}
		WxApp wxApp = r.getData();
		if(wxApp == null){
			throw new RuntimeException("无此公众号："+loginDTO.getAppId()+ "；请在后台添加");
		}
		TenantContextHolder.setTenantId(wxApp.getTenantId());
		if(!request.getHeader(PortalConstants.HEADER_TENANT_ID).equals(wxApp.getTenantId())){
			throw new RuntimeException("该appID不属于该租户ID");
		}
		//通过code获取微信用户信息
		R<WxUser> r1 = feignWxUserService.code2WxUserMp(loginDTO, SecurityConstants.FROM_IN);
		if(!r1.isOk()){
			throw new RuntimeException(r1.getMsg());
		}
		WxUser wxUser = r1.getData();
		UserInfo userInfo;
		if(StrUtil.isBlank(wxUser.getId())) {
			//新增微信用户
			wxUser.setAppId(wxApp.getId());
			wxUser.setAppType(wxApp.getAppType());
			wxUser.setSubscribe(WxConstant.SUBSCRIBE_TYPE_WEBLICENS);
			R<WxUser> r4 = feignWxUserService.saveOrUpdate(wxUser, SecurityConstants.FROM_IN);
			if(!r4.isOk()){
				throw new RuntimeException(r4.getMsg());
			}
			wxUser = r4.getData();
		}
		if(StrUtil.isNotBlank(wxUser.getMallUserId())){
			userInfo = getUserInfoService().getById(wxUser.getMallUserId());
			if(userInfo != null){
				//分销关系上级绑定，用户类型 1、老用户
				userInfo.setSharerUserCode(loginDTO.getSharerUserCode());
				this.parentBind(MallConstants.DISTRIBUTION_USER_TYPE_1,userInfo);
			}else{
				userInfo = new UserInfo();
			}
		}else{
			//同一微信开放平台账号下的不同应用 同一用户的unionId是相同的
			if(StrUtil.isNotBlank(wxUser.getUnionId())){
				//如果该公众号用户有unionId，继续查找该unionId的其他小程序、公众号用户是否已经绑定商城用户，如有unionId相同的其他小程序、公众号用户，说明是同一人；直接绑定相同的商城用户，无需再次登录绑定
				R<List<WxUser>> r2 = feignWxUserService.getByUnionIdInside(wxUser.getUnionId(), wxUser.getId(), SecurityConstants.FROM_IN);
				List<WxUser> listWxUser = r2.getData();
				if(listWxUser != null && listWxUser.size() > 0){
					//取第一个unionId相同的微信用户
					WxUser wxUser2 = listWxUser.get(0);
					//查出此微信用户绑定的商城用户
					userInfo = getUserInfoService().getById(wxUser2.getMallUserId());
					//将该小程序用户绑定到该商城用户
					wxUser.setMallUserId(wxUser2.getMallUserId());
					feignWxUserService.saveOrUpdate(wxUser, SecurityConstants.FROM_IN);
					//分销关系上级绑定，用户类型 1、老用户
					userInfo.setSharerUserCode(loginDTO.getSharerUserCode());
					this.parentBind(MallConstants.DISTRIBUTION_USER_TYPE_1,userInfo);
				}else{
					userInfo = new UserInfo();
				}
			}else{
				userInfo = new UserInfo();
			}
		}
		String thirdSessionKey = "wx:" + wxUser.getId() + ":" + UUID.randomUUID();
		ThirdSession thirdSession = new ThirdSession();
		thirdSession.setTenantId(wxApp.getTenantId());
		thirdSession.setAppId(wxApp.getId());
		thirdSession.setWxUserId(wxUser.getId());
		thirdSession.setOpenId(wxUser.getOpenId());
		thirdSession.setUserId(userInfo.getId());
		//将3rd_session和用户信息存入redis，并设置过期时间
		String key = ThirdSessionInterceptor.getSessionRedisKey(thirdSessionKey);
		redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(thirdSession) , CacheConstants.TIME_OUT_SESSION, TimeUnit.HOURS);
		userInfo.setThirdSession(thirdSessionKey);
		return userInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public UserInfo updateByMa(WxOpenDataDTO wxOpenDataDTO) {
		//修改微信用户信息
		R<WxUser> r = feignWxUserService.updateByMaInside(wxOpenDataDTO, SecurityConstants.FROM_IN);
		if(!r.isOk()){
			throw new RuntimeException(r.getMsg());
		}
		UserInfo userInfo = null;
		//修改商城用户信息
		WxUser wxUser = r.getData();
		if(wxUser != null && StrUtil.isNotBlank(wxUser.getMallUserId())){
			userInfo = getUserInfoService().getById(wxUser.getMallUserId());
			userInfo.setNickName(wxUser.getNickName());
			userInfo.setHeadimgUrl(wxUser.getHeadimgUrl());
//			userInfo.setSex(wxUser.getSex());
//			userInfo.setCity(wxUser.getCity());
//			userInfo.setCountry(wxUser.getCountry());
//			userInfo.setProvince(wxUser.getProvince());
			userInfo.setUpdateTime(LocalDateTime.now());
			this.updateById(userInfo);
		}
		return userInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public UserInfo updateByMp(WxOpenDataDTO wxOpenDataDTO) {
		R<WxUser> r = feignWxUserService.updateByMpInside(wxOpenDataDTO, SecurityConstants.FROM_IN);
		if(!r.isOk()){
			throw new RuntimeException(r.getMsg());
		}
		UserInfo userInfo = null;
		//修改商城用户信息
		WxUser wxUser = r.getData();
		if(wxUser != null && StrUtil.isNotBlank(wxUser.getMallUserId())){
			userInfo = getUserInfoService().getById(wxUser.getMallUserId());
			userInfo.setNickName(wxUser.getNickName());
			userInfo.setHeadimgUrl(wxUser.getHeadimgUrl());
//			userInfo.setSex(wxUser.getSex());
//			userInfo.setCity(wxUser.getCity());
//			userInfo.setCountry(wxUser.getCountry());
//			userInfo.setProvince(wxUser.getProvince());
			userInfo.setUpdateTime(LocalDateTime.now());
			this.updateById(userInfo);
		}
		return userInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public UserInfo saveUserInfo(UserInfo userInfo) {
		if(StrUtil.isBlank(userInfo.getId())){
			//获取用户初始积分
			PointsConfig pointsConfig = pointsConfigService.getOne(Wrappers.emptyWrapper());
			int initPosts = pointsConfig != null ? pointsConfig.getInitPosts() : 0;
			//新增商城用户
			userInfo.setUserGrade(MallConstants.USER_GRADE_0);
			if(StrUtil.isBlank(userInfo.getHeadimgUrl())){//没有头像则入默认头像
				userInfo.setHeadimgUrl(mallConfigProperties.getUserDefaultAvatar());
			}
			if(StrUtil.isBlank(userInfo.getNickName())){//没有昵称则入默认昵称
				String nickName = SensitiveUtils.mobilePhone(userInfo.getPhone());
				userInfo.setNickName(nickName);
			}
			this.save(userInfo);
			//新增用户积分
			UserPoints userPoints = new UserPoints();
			userPoints.setUserId(userInfo.getId());
			userPoints.setPointsCurrent(initPosts);
			userPointsMapper.insert(userPoints);
			if(initPosts > 0){
				//新增积分变动记录
				PointsRecord pointsRecord = new PointsRecord();
				pointsRecord.setUserId(userInfo.getId());
				pointsRecord.setAmount(initPosts);
				pointsRecord.setRecordType(MallConstants.POINTS_RECORD_TYPE_0);
				pointsRecord.setDescription("用户初始积分");
				pointsRecordService.save(pointsRecord);
			}
		}else{
			this.updateById(userInfo);
		}
		userInfo = getUserInfoService().getById(userInfo.getId());
		return userInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public UserInfo loginByPhoneWx(ThirdSession thirdSession, String phone, String key, String sharerUserCode) {
		//先查询该手机号是不是商城用户
		UserInfo userInfo = this.getOne(Wrappers.<UserInfo>lambdaQuery()
				.eq(UserInfo::getPhone,phone));
		String userType = MallConstants.DISTRIBUTION_USER_TYPE_1;
		//先获取微信用户信息
		WxUser wxUser = feignWxUserService.getById(thirdSession.getWxUserId(), SecurityConstants.FROM_IN).getData();
		if(userInfo == null){//不是商城用户，则新增
			userInfo = new UserInfo();
			userType = MallConstants.DISTRIBUTION_USER_TYPE_2;
			//新增商城用户
			userInfo.setAppType(PortalConstants.CLIENT_TYPE_MA);
			userInfo.setAppId(wxUser.getAppId());
		}
		if (StrUtil.isBlank(userInfo.getPhone())) {
			userInfo.setPhone(phone);
		}
		if (StrUtil.isBlank(userInfo.getNickName())) {
			userInfo.setNickName(wxUser.getNickName());
		}
//		if (StrUtil.isBlank(userInfo.getCity())) {
//			userInfo.setCity(wxUser.getCity());
//		}
//		if (StrUtil.isBlank(userInfo.getCountry())) {
//			userInfo.setCountry(wxUser.getCountry());
//		}
		if (StrUtil.isBlank(userInfo.getHeadimgUrl())) {
			userInfo.setHeadimgUrl(wxUser.getHeadimgUrl());
		}
//		if (StrUtil.isBlank(userInfo.getProvince())) {
//			userInfo.setProvince(wxUser.getProvince());
//		}
//		if (StrUtil.isBlank(userInfo.getSex())) {
//			userInfo.setSex(wxUser.getSex());
//		}
		//更新或新增商城用户
		userInfo = this.saveUserInfo(userInfo);
		//分销关系上级绑定
		userInfo.setSharerUserCode(sharerUserCode);
		this.parentBind(userType,userInfo);

		String mallUserId = userInfo.getId();
		wxUser.setMallUserId(mallUserId);
		wxUser.setPhone(phone);

		userInfo.setThirdSession(StrUtil.removeAll(key,ThirdSessionInterceptor.getSessionRedisKey("")));
		//更新微信用户
		feignWxUserService.saveOrUpdate(wxUser, SecurityConstants.FROM_IN);
		//更新redis中的thirdSession
		thirdSession.setUserId(mallUserId);
		thirdSession.setOpenId(wxUser.getOpenId());
		redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(thirdSession) , CacheConstants.TIME_OUT_SESSION, TimeUnit.HOURS);
		//处理微信用户登录、退出时的redis缓存
		this.wxUserRedisHandle(wxUser,key);
		return userInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public UserInfo loginByPhone(HttpServletRequest request, UserInfoLoginDTO userInfoLoginDTO) {
		//通过手机号登录
		UserInfo userInfo = this.getOne(Wrappers.<UserInfo>query().lambda()
				.eq(UserInfo::getPhone, userInfoLoginDTO.getPhone()));
		String userType = MallConstants.DISTRIBUTION_USER_TYPE_1;
		if(userInfo == null){
			userType = MallConstants.DISTRIBUTION_USER_TYPE_2;
			//新用户先注册
			userInfo = new UserInfo();
			userInfo.setAppType(ApiUtil.getClientType(request));
			userInfo.setAppId(ApiUtil.getAppId(request));
			userInfo.setPhone(userInfoLoginDTO.getPhone());
			//更新或新增商城用户
			userInfo = this.saveUserInfo(userInfo);
		}
		//登录
		userInfo = this.login(request,userInfo);
		//分销关系上级绑定
		userInfo.setSharerUserCode(userInfoLoginDTO.getSharerUserCode());
		this.parentBind(userType,userInfo);
		return userInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public UserInfo login(HttpServletRequest request, UserInfo userInfo) {
		String clientTypeHeader = ApiUtil.getClientType(request);
		String appIdHeader = ApiUtil.getAppId(request);
		ThirdSession thirdSession;
		String key;
		if(PortalConstants.CLIENT_TYPE_H5.equals(clientTypeHeader) || PortalConstants.CLIENT_TYPE_H5_PC.equals(clientTypeHeader) ||
				(PortalConstants.CLIENT_TYPE_H5_WX.equals(clientTypeHeader) && StrUtil.isBlank(appIdHeader)) ||
				PortalConstants.CLIENT_TYPE_APP.equals(clientTypeHeader)){//普通h5端、没有appId的微信H5、APP
			String thirdSessionKey = UUID.randomUUID().toString();
			thirdSession = new ThirdSession();
			thirdSession.setTenantId(userInfo.getTenantId());
			thirdSession.setUserId(userInfo.getId());
			//将3rd_session和用户信息存入redis，并设置过期时间
			key = ThirdSessionInterceptor.getSessionRedisKey(thirdSessionKey);

			userInfo.setThirdSession(thirdSessionKey);
		}else{//小程序、公众号端，更新thirdSession即可
			thirdSession = ThirdSessionHolder.getThirdSession();
			String thirdSessionHeader = request.getHeader(PortalConstants.HEADER_THIRDSESSION);
			key = ThirdSessionInterceptor.getSessionRedisKey(thirdSessionHeader);
			thirdSession.setUserId(userInfo.getId());

			userInfo.setThirdSession(thirdSessionHeader);
			//先获取微信用户信息
			WxUser wxUser = feignWxUserService.getById(thirdSession.getWxUserId(), SecurityConstants.FROM_IN).getData();
			wxUser.setMallUserId(userInfo.getId());
			thirdSession.setOpenId(wxUser.getOpenId());
			//更新微信用户
			feignWxUserService.saveOrUpdate(wxUser, SecurityConstants.FROM_IN);
			//处理微信用户登录、退出时的redis缓存
			this.wxUserRedisHandle(wxUser,key);
		}
		redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(thirdSession) , CacheConstants.TIME_OUT_SESSION, TimeUnit.HOURS);
		return userInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public UserInfo logout(HttpServletRequest request) {
		//获取thirdSession
		ThirdSession thirdSession = ThirdSessionHolder.getThirdSession();
		if(thirdSession == null){
			return null;
		}
		String clientTypeHeader = ApiUtil.getClientType(request);
		String appIdHeader = ApiUtil.getAppId(request);
		String thirdSessionHeader = request.getHeader(PortalConstants.HEADER_THIRDSESSION);
		String key = ThirdSessionInterceptor.getSessionRedisKey(thirdSessionHeader);
		//查询出来当前商城用户信息
		UserInfo userInfo = getUserInfoService().getById(thirdSession.getUserId());
		if(PortalConstants.CLIENT_TYPE_H5.equals(clientTypeHeader) || PortalConstants.CLIENT_TYPE_H5_PC.equals(clientTypeHeader) ||
				(PortalConstants.CLIENT_TYPE_H5_WX.equals(clientTypeHeader) && StrUtil.isBlank(appIdHeader))||
				PortalConstants.CLIENT_TYPE_APP.equals(clientTypeHeader)){//普通h5端或没有appId的微信H5
			//删除redis中的session
			redisTemplate.delete(key);
			return null;
		}else{//微信用户
			//先获取微信用户信息
			WxUser wxUser = feignWxUserService.getById(thirdSession.getWxUserId(), SecurityConstants.FROM_IN).getData();
			wxUser.setMallUserId("");
			//移除微信用户的商城用户ID关联
			feignWxUserService.saveOrUpdate(wxUser, SecurityConstants.FROM_IN);
			//更新redis中的thirdSession
			thirdSession.setUserId(null);
			redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(thirdSession) , CacheConstants.TIME_OUT_SESSION, TimeUnit.HOURS);
			//处理微信用户登录、退出时的redis缓存
			this.wxUserRedisHandle(wxUser,key);
			userInfo = new UserInfo();
			userInfo.setThirdSession(StrUtil.removeAll(key,ThirdSessionInterceptor.getSessionRedisKey("")));
			return userInfo;
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public UserInfo register(UserInfo userInfo) {
		userInfo.setPassword(ENCODER.encode(userInfo.getPassword()));
		userInfo = this.saveUserInfo(userInfo);
		return userInfo;
	}

	@Override
	public IPage<UserInfo> page1(IPage<UserInfo> page, UserInfo userInfo) {
		return baseMapper.selectPage1(page,userInfo);
	}

	@Override
	public void updateProCity(HttpServletRequest request, String userId) {
		Map<String, String> map = IpUtils.getProCity(request.getRemoteAddr());
		if(map != null){
			UserInfo userInfo = new UserInfo();
			userInfo.setId(userId);
			String pro = map.get("pro");
			if(StrUtil.isNotEmpty(pro)){
				userInfo.setProvince(pro);
			}
			String city = map.get("city");
			if(StrUtil.isNotEmpty(city)){
				userInfo.setCity(city);
			}
			this.updateById(userInfo);
		}
	}

	/**
	 * 处理微信用户登录、退出时的redis缓存
	 * @param wxUser
	 * @param key
	 */
	public void wxUserRedisHandle(WxUser wxUser, String key){
		if(wxUser != null){
			//清空该用户其他地方登录的缓存
			String key1 = ThirdSessionInterceptor.getSessionRedisKey("") + "wx:" + wxUser.getId() + ":*";
			Set<String> keys1 = redisTemplate.keys(key1);
			keys1.remove(key);
			if (CollectionUtil.isNotEmpty(keys1)) {
				redisTemplate.delete(keys1);
			}

			if(StrUtil.isNotBlank(wxUser.getUnionId())){
				//如该微信用户有unionId，则清空相同unionId的其他用户缓存
				R<List<WxUser>> r2 = feignWxUserService.getByUnionIdInside(wxUser.getUnionId(), wxUser.getId(), SecurityConstants.FROM_IN);
				List<WxUser> listWxUser = r2.getData();
				listWxUser.forEach(wxUser2 -> {
					String key2 = ThirdSessionInterceptor.getSessionRedisKey("") + "wx:" + wxUser2.getId() + ":*";
					Set<String> keys2 = redisTemplate.keys(key2);
					if (CollectionUtil.isNotEmpty(keys2)) {
						redisTemplate.delete(keys2);
					}
				});
			}
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void parentBind(String userType, UserInfo userInfo) {
		if(StrUtil.isNotBlank(userInfo.getSharerUserCode())){
			//获取分销配置
			DistributionConfig distributionConfig = distributionConfigService.getByTenantId(TenantContextHolder.getTenantId());
			if(distributionConfig != null && CommonConstants.YES.equals(distributionConfig.getEnable())){//分销开启才往下走
				//获取当前用户信息
				UserInfo userInfo2 = getUserInfoService().getById(userInfo.getId());
				if(StrUtil.isBlank(userInfo2.getParentId())){//没有上级ID的用户才往下走
					String bindType = distributionConfig.getBindType();
					//销关系绑定为所有用户或分销关系绑定为新用户且当前用户为新用户  才往下走
					if(MallConstants.DISTRIBUTION_BINDTYPE_1.equals(bindType) ||
							(MallConstants.DISTRIBUTION_BINDTYPE_2.equals(bindType) && MallConstants.DISTRIBUTION_USER_TYPE_2.equals(userType))){
						//获取分享人的用户信息
						UserInfo userInfo3 = this.getOne(Wrappers.<UserInfo>query().lambda()
								.eq(UserInfo::getUserCode, userInfo.getSharerUserCode()));
						if(userInfo3 != null && !userInfo3.getId().equals(userInfo.getId())){
							//设置当前用户的上级
							userInfo2.setParentId(userInfo3.getId());
							this.updateById(userInfo2);
						}
					}
				}
			}
		}
	}

}
